#include "../ocl/driver.h"


static ocl_driver    OCL;
static ocl_driver *__OpenCL = NULL;

ocl_driver *ocl_driver_load( void )
{
	static const char fn[] = "[ocl_driver_init]"; 
	ocl_errno = CL_SUCCESS;
	if( ! __OpenCL )
	{
		__OpenCL = & OCL;
		memset( __OpenCL, 0, sizeof(ocl_driver) );
	}
	else 
		return __OpenCL;
	
	/*--------------------*/
	/* query #platforms  */
	/*------------------*/
	if( ocl_logfile ) fprintf( ocl_logfile, "%s Query #platforms\n",fn); 
	if( CL_SUCCESS != ( ocl_errno = clGetPlatformIDs( 0, NULL, & OCL.num_platforms ) ) )
	{
		goto ERROR;	}
	
	/*-----------------------------------*/
	/* allocate memory for platforms_id */
	/*---------------------------------*/
	if( ocl_logfile ) fprintf( ocl_logfile, "%s CALLOC(cl_platform_id,%u)\n", fn, OCL.num_platforms);
	if( NULL == ( OCL.platforms_id = MDS_CALLOC_AS(cl_platform_id,OCL.num_platforms) ) )
	{
		goto ERROR;
	}
	
	/*------------*/
	/* fill them */
	/*----------*/
	if( ocl_logfile ) fprintf( ocl_logfile, "%s Read platforms_id\n", fn);
	if( CL_SUCCESS != ( ocl_errno = clGetPlatformIDs( OCL.num_platforms, OCL.platforms_id, NULL ) ) )
	{
		goto ERROR;
	}
	
	/*-----------------------------------*/
	/* allocate memory platforms        */
	/*---------------------------------*/
	if( ocl_logfile ) fprintf( ocl_logfile, "%s CALLOC(ocl_platform,%u)\n", fn, OCL.num_platforms);
	if( NULL == (OCL.platforms = MDS_CALLOC_AS(ocl_platform,OCL.num_platforms) ) )
	{
		goto ERROR;
	}
	
	/*----------------------*/
	/* build the platforms */
	/*--------------------*/
	if( ocl_logfile ) fprintf( ocl_logfile, "%s Load each platform...\n", fn );
	while( OCL.reserved < OCL.num_platforms )
	{
		if( ocl_logfile ) fprintf( ocl_logfile, "%s ================ platform %u ================\n", fn , OCL.reserved);
		if( ocl_platform_load(  OCL.platforms_id[OCL.reserved], 
							  & OCL.platforms[OCL.reserved]    ) < 0 )
		{
			goto ERROR;
		}
		++OCL.reserved;
	}
	
	/*------------*/
	/* all done  */
	/*----------*/
	assert( 0 == OCL.num_devices );
	{
		register cl_uint i;
		for( i=0; i < OCL.num_platforms; ++i )
		{
			OCL.num_devices += OCL.platforms[i].num_devices;
		}
		if( ocl_logfile )  fprintf( ocl_logfile, "%s total num_devices=%u\n", fn, OCL.num_devices );
	}
	return __OpenCL;
	
	
ERROR:
	ocl_driver_quit();
	return NULL;
}


void ocl_driver_quit(void)
{
	static const char fn[] = "[ocl_driver_quit]";
	if( __OpenCL )
	{
		if( ocl_logfile ) fprintf( ocl_logfile, "%s\n", fn);
		if( OCL.platforms )
		{
			while( OCL.reserved > 0 )
			{
				ocl_platform_quit( & OCL.platforms[ --OCL.reserved ] );
			}
			MDS_FREE_AS(ocl_platform,OCL.platforms,OCL.num_platforms);
		}
		
		if( OCL.platforms_id ) MDS_FREE_AS(cl_platform_id,OCL.platforms_id,OCL.num_platforms);
		
		memset( __OpenCL, 0, sizeof(ocl_driver) );
		__OpenCL = NULL;
	}
}

ocl_device *ocl_driver_device( cl_device_id id )
{
	if( __OpenCL )
	{
		cl_uint i=0;
		for( ; i < OCL.num_platforms; ++i )
		{
			ocl_platform *p = & OCL.platforms[ i ];
			cl_uint       j = 0;
			for( ; j < p->num_devices; ++j )
			{
				ocl_device *d = p->devices + j;
				if( id == d->id )
					return d;
			}
		}
	}
	
	return NULL;
}

